#ifndef SIGNAL_HPP
#define SIGNAL_HPP
#include <list>
#include"xfunction.hpp"                 //包装信号的发送者指针与信号类型，支持变参
#include<thread>
#include<map>
#include"XThrdSafeQueue.hpp"  
#include "utils.hpp"   
#include<future>  

//基于C++实现的信号槽机制https://gitee.com/LonelyPolarbear/xsignalslot.git
namespace SIG
{   
    //信号槽连接类型
    enum class connectType{
        directConnection = 0,
        queueConnection = 1,
        queueBlockConnection = 2
    };

    enum class passMsgType{
        sendMessage = 0,
        postMessage = 1
    };
    
    struct ACTION_MSG{
        std::function<void()> fn;
        void* reciver = nullptr;    //sigReciver
    };
    
    //抽象信号类
    class AbsSignal{
    public:
        virtual ~AbsSignal(){}

        //当信号的接收者析构时，应清除与该接收者绑定的信号的槽函数列表
        virtual void deleteReciver(void *p){};
        
        virtual void delteThrdConnectReciver(unsigned int){}
        
        //当线程执行结束后，应清除运行在该线程的信号绑定的槽函数。
        void static cleareThrdConnectReciver(unsigned int id){
            for(auto&w:m_signals){
                auto s = w.lock();
                if(s)
                    s->delteThrdConnectReciver(id);
            }
        }
        
        //记录所有创建的信号
        static bool addWeakPtrToList(std::weak_ptr<SIG::AbsSignal> w){
            m_signals.push_back(w);
            return true;
        };
public:
        inline static list<unsigned int> m_thrdIDlists;
        inline static std::list<std::weak_ptr<SIG::AbsSignal>> m_signals;
    };
    inline AbsSignal m_thrdIDlists;

    class sigReciver
    {
    public:
        sigReciver()
        {
            s_mutex.lock();
            s_recivers.push_back(this);
            s_mutex.unlock();
        }
        virtual ~sigReciver()
        {   
            while(!s_mutex.try_lock());
            s_recivers.remove(this);
            s_mutex.unlock();
            // 存储所有自己绑定的信号，当自己析构时，通知信号
            for (std::weak_ptr<SIG::AbsSignal> &w : m_signals)
            {
                auto s = w.lock();
                if (s)
                    s->deleteReciver((void *)this);
            }
        }
        static bool isExits(void *reciver)
        {
            sigReciver *check = (sigReciver *)(reciver);
            auto found = std::find(s_recivers.begin(), s_recivers.end(), check);
            if (found == s_recivers.end())
                return false;
            return true;
        }

        static void deleteLater(sigReciver *p){
            std::thread t([p](){
                delete p;
            });
            t.detach();
        }

    public:
        template <typename T>
        void recordSignal(T v)
        {
            m_signals.push_back(v);
        }

    protected:
        std::list<std::weak_ptr<SIG::AbsSignal>> m_signals;
        inline static std::list<sigReciver *> s_recivers;
    public:
        inline static std::mutex s_mutex;
    };
    inline sigReciver s_recivers;
    inline sigReciver s_mutex;

    //用户实现线程间信号通信需要调用的接口
    struct sig_thrd
    {
        void static Init_CurrentThrdSignalBuffer(){
            std::thread::id tid = std::this_thread::get_id();
	        unsigned int nid = *(unsigned int *)&tid;
            msgMaps.insert({nid, XThrdSafeQueue<ACTION_MSG>()});
            AbsSignal::m_thrdIDlists.push_back(nid);
        }

        //当线程关闭时，线程队列还有消息，应将其销毁
        void static clear_CurrentThrdSignalBuffer(){
            std::thread::id tid = std::this_thread::get_id();
	        unsigned int nid = *(unsigned int *)&tid;
            msgMaps.erase(nid); 
            AbsSignal::cleareThrdConnectReciver(nid);
        }

        ACTION_MSG static getMessageFromCurrentThrdSignalBuffer(int msec){
            std::thread::id tid = std::this_thread::get_id();
	        unsigned int nid = *(unsigned int *)&tid;
            std::optional<ACTION_MSG> msg = msgMaps[nid].getMessage(msec);
            if(msg)
                return *msg;
            else
                return ACTION_MSG();
        }
        inline static std::map<unsigned int, XThrdSafeQueue<ACTION_MSG> > msgMaps;
    };
    inline sig_thrd msgMaps;

    //暴露外部的接口
    //成员函数绑定
    template <typename sendertype, typename signaltype, typename recivertype, typename slottype,
                    typename T =std::enable_if_t<is_class_v<remove_pointer_t<recivertype>>&&
                                                                    (is_member_function_pointer_v<slottype> || is_class_v<slottype>)
                                                                     >
                    >
    void connect(sendertype *sender, signaltype signalObj, recivertype recv, slottype f,
            connectType type= connectType::directConnection,passMsgType msgType  = passMsgType::postMessage )
    {   
        utils::getClassInnerPointer(recv)->recordSignal((sender->*signalObj));
        (sender->*signalObj)->connect(recv, f,type,msgType);
    }
    
    //全局函数和函数对象绑定
    template <typename sendertype, typename signaltype,  typename slottype>
    void connect(sendertype *sender, signaltype signalObj, slottype f,
            connectType type= connectType::directConnection,passMsgType msgType  = passMsgType::postMessage)
    {
        (sender->*signalObj)->connect(f,type,msgType);
    }

    //成员函数解绑定
    template <typename sendertype, typename signaltype, typename recivertype, typename slottype,
                    typename T =std::enable_if_t<is_class_v<std::remove_pointer_t<recivertype>>&& is_member_function_pointer_v<slottype>>>
    void disconnect(sendertype *sender, signaltype signalObj, recivertype recv, slottype f,
            connectType type= connectType::directConnection,passMsgType msgType  = passMsgType::postMessage )
    {   
        (sender->*signalObj)->disconnect(recv,f,type,msgType);
    }

    //函数解绑定,函数对象不允许解绑定
    template <typename sendertype, typename signaltype,  typename slottype,typename T =std::enable_if_t<std::is_pointer_v<slottype>>>
    void disconnect(sendertype *sender, signaltype signalObj, slottype f,
            connectType type= connectType::directConnection,passMsgType msgType  = passMsgType::postMessage)
    {
        (sender->*signalObj)->disconnect(f,type,msgType);
    }

    //单次触发--成员函数
    template<typename reciver,typename slottype,typename... Args,
                    typename T = std::enable_if_t<is_class_v<std::remove_pointer_t< reciver>>&& 
                                           is_member_function_pointer_v<slottype>>
                    >
    void SingleSlot(reciver recv,slottype f,Args&&...args){
        xfunction<void()> xf(recv,f,std::forward<Args>(args)...);    //第一次包装
        ACTION_MSG wrapper_fun = {std::bind(xf), utils::getClassInnerPointer(recv)};                            //第二次包装
        std::thread::id tid = std::this_thread::get_id();
	    unsigned int nid = *(unsigned int *)&tid;
        SIG::sig_thrd::msgMaps[nid].postmessge(wrapper_fun);
    }

    //单次触发--仿函数或普通函数
    template<typename slottype,typename... Args>
    void SingleSlot(slottype&& f,Args&&...args){
        ACTION_MSG wrapper_fun = {std::bind(std::forward<slottype>(f),std::forward<Args>(args)...),nullptr};  
        std::thread::id tid = std::this_thread::get_id();
	    unsigned int nid = *(unsigned int *)&tid;
        SIG::sig_thrd::msgMaps[nid].postmessge(wrapper_fun);
    }

    //信号类，实现信号的连接与发射
    template<typename ...Args>
    class xsignal:public AbsSignal{
    public:
        struct slotCfg{
            xfunction<void(Args...)> fun;
            SIG::connectType type;
            unsigned int thrdId;
            SIG::passMsgType msgType;

            void* funID;                    //解绑时使用
            void *other = nullptr;     //解绑时使用,对象指针

            slotCfg& operator=(const slotCfg& rths) = default;

            bool operator==(const slotCfg& rths) const{
                return this->type == rths.type &&
                           this->funID == rths.funID &&
                           this->msgType == rths.msgType &&
                           this->other == rths.other; 
                           this->thrdId == rths.thrdId;
            }

            bool equalIgnoreThrdId(const slotCfg& rths){
                return this->type == rths.type &&
                           this->funID == rths.funID &&
                           this->msgType == rths.msgType &&
                           this->other == rths.other; 
            }
        };          
public:
            //信号槽连接-成员函数绑定
            template<class desttype,typename ...types>
            void connect(desttype pclass, void(getClassType_t<std::remove_pointer_t<desttype>>::*f)(types...),SIG::connectType type,passMsgType msgType){
                void *other = utils::getClassInnerPointer(pclass);
                void* funID =utils::pointer_cast<void*>(f);
                std::thread::id tid = std::this_thread::get_id();
                unsigned int nid = *(unsigned int*)&tid;       
                slotCfg msg{xfunction<void(Args...)>(pclass,f),type,nid,msgType,funID,other};

                std::unique_lock lock(slots_mutex);
                m_connected_slots.push_back(msg);
            }

            //指定接收者的仿函数和全局函数绑定
            template<class desttype,typename functor>
            void connect(desttype pclass, functor f,SIG::connectType type,passMsgType msgType){
                void *other = utils::getClassInnerPointer(pclass);
                void* funID =utils::getFunctorOrGlobalFunPointer(f);
                std::thread::id tid = std::this_thread::get_id();
                unsigned int nid = *(unsigned int*)&tid;
                slotCfg msg{xfunction<void(Args...)>(f),type,nid,msgType,funID,other};

                std::unique_lock lock(slots_mutex);
                m_connected_slots.push_back(msg);
            }

            //专门设计解决状态机模式框架中的问题，如不需要使用状态机框架可忽略
            template<class desttype,typename functor>
            void connect(desttype pclass, functor f,unsigned int thrdid){
                void *other = utils::getClassInnerPointer(pclass);
                void* funID =utils::getFunctorOrGlobalFunPointer(f);
                slotCfg msg{xfunction<void(Args...)>(f),SIG::connectType::queueConnection,thrdid,SIG::passMsgType::postMessage,funID,other};
                
                std::unique_lock lock(slots_mutex);
                m_connected_slots.push_back(msg);
            }

            //不指定接收者的仿函数和全局函数绑定
            template<typename F>
            void connect(F f,SIG::connectType type,passMsgType msgType)
            {
                void *other = nullptr;
                void* funID =utils::getFunctorOrGlobalFunPointer(f);
                std::thread::id tid = std::this_thread::get_id();
                unsigned int nid = *(unsigned int*)&tid;
                slotCfg msg{xfunction<void(Args...)>(f),type,nid,msgType,funID,other};

                std::unique_lock lock(slots_mutex);
                m_connected_slots.push_back(msg);
            }

            //解绑成员函数指针,desttype是指针或智能指针
            template<class desttype,typename ...types>
            void disconnect(desttype pclass, void(getClassType_t<std::remove_pointer_t<desttype>>::*f)(types...),SIG::connectType type,passMsgType msgType)
            {
                void *other = utils::getClassInnerPointer(pclass);
                void* funID =utils::pointer_cast<void*>(f);
                std::thread::id tid = std::this_thread::get_id();
                unsigned int nid = *(unsigned int*)&tid;

                //使用std::find_if在目前所用的gcc8.1下编译报错，在msvc16下可以编译通过
                std::unique_lock lock(slots_mutex);
                auto Found = m_connected_slots.begin();
                slotCfg tmp{xfunction<void(Args...)>(),type,nid,msgType,funID,other};
                for(auto& msg:m_connected_slots){
                    if(msg.type == SIG::connectType::directConnection){
                        //directConnection不考虑线程ID
                        if(msg.equalIgnoreThrdId(tmp) && msg.funID != nullptr){
                            Found = std::find(m_connected_slots.begin(),m_connected_slots.end(),msg);
                            m_connected_slots.remove(*Found);       //一次disconnect只解绑一个连接
                            break;
                        }
                    }
                    else if(msg==tmp && msg.funID != nullptr)
                    {
                        //msg.funID == nullptr 表示绑定的是函数对象，是不允许解绑定的
                        Found = std::find(m_connected_slots.begin(),m_connected_slots.end(),msg);
                        m_connected_slots.remove(*Found);       //一次disconnect只解绑一个连接
                        break;
                    }
                }        
            }
            
            //解绑函数指针
            template<typename F,typename T =std::enable_if_t<std::is_pointer_v<F>> >
            void disconnect(F f,SIG::connectType type,passMsgType msgType)
            {
                void *other = nullptr;
                void *funID = (void*)f;
                std::thread::id tid = std::this_thread::get_id();
                unsigned int nid = *(unsigned int*)&tid;

                //使用std::find_if在目前所用的gcc8.1下编译报错，在msvc16下可以编译通过
                std::unique_lock lock(slots_mutex);
                auto Found = m_connected_slots.begin();
                slotCfg tmp{xfunction<void(Args...)>(),type,nid,msgType,funID,other};
                for(auto& msg:m_connected_slots){
                    if(msg.type == SIG::connectType::directConnection){
                        //directConnection不考虑线程ID
                        if(msg.equalIgnoreThrdId(tmp)){
                            Found = std::find(m_connected_slots.begin(),m_connected_slots.end(),msg);
                            m_connected_slots.remove(*Found);       //一次disconnect只解绑一个连接
                            break;
                        }
                    }
                    else if(msg==tmp)
                    {
                        Found = std::find(m_connected_slots.begin(),m_connected_slots.end(),msg);
                        m_connected_slots.remove(*Found);       //一次disconnect只解绑一个连接
                        break;
                    }
                }      
            }

            template<typename ...types>
            void operator()(types&&... args){
                emit(std::forward<types>(args)...);
            }

            //当接收者析构时，应销毁掉信号中记录的槽函数
            virtual void deleteReciver(void *p){
                std::unique_lock lock(slots_mutex);
                while(1){
                    bool isEnd = true;
                    for (slotCfg &tmp : m_connected_slots)
                    {
                        if (tmp.other == p && p != nullptr)
                        {
                            isEnd = false;
                            break;
                        }
                    }

                    if(isEnd==true){
                        break;  //结束while循环
                    }
      
                    for (slotCfg &tmp : m_connected_slots)
                    {
                        if (tmp.other == p && p != nullptr)
                        {
                            m_connected_slots.remove(tmp);
                            break; //结束for循环
                        }
                    }
                }
            }

            virtual void delteThrdConnectReciver(unsigned int id){
                std::unique_lock lock(slots_mutex);
                while(1){
                    bool isEnd = true;
                    for (slotCfg &tmp : m_connected_slots)
                    {
                        if (tmp.thrdId == id)
                        {
                            isEnd = false;
                            break;
                        }
                    }

                    if(isEnd==true){
                        break;  //结束while循环
                    }
      
                    for (slotCfg &tmp : m_connected_slots)
                    {
                        if (tmp.thrdId == id)
                        {
                            m_connected_slots.remove(tmp);
                            break; //结束for循环
                        }
                    }
                }
            }
private:
            template<typename ...types>
            void emit(types&&... args)
            {
                slots_mutex.lock();
                std::list<slotCfg> tmp_connected_slots = m_connected_slots;
                slots_mutex.unlock();

                for(auto&p:tmp_connected_slots){
                    //直接连接
                    if(p.type == SIG::connectType::directConnection){
                        sigReciver::s_mutex.lock();
                        if(sigReciver::isExits(p.other) || p.other== nullptr){
                            p.fun(std::forward<types>(args)...);
                        }else{
                            std::cout<<"sigReciver does not exist!"<<std::endl;
                        }
                        sigReciver::s_mutex.unlock();
                    }
                    else if(p.type == SIG::connectType::queueConnection){
                        ACTION_MSG wrapper_fun = {std::bind(p.fun,std::forward<types>(args)...),p.other};
                        if(p.msgType ==passMsgType::postMessage )
                            SIG::sig_thrd::msgMaps[p.thrdId].postmessge(wrapper_fun);
                        else
                            SIG::sig_thrd::msgMaps[p.thrdId].sendmessage(wrapper_fun);
                    }else{
                        if(p.type == SIG::connectType::queueBlockConnection){
                            std::promise<void> bolckPromise;
                            std::future<void> blockFuture = bolckPromise.get_future();
                            ACTION_MSG wrapper_fun = {std::bind(p.fun,&bolckPromise,std::forward<types>(args)...),p.other};
                        
                            if(p.msgType ==passMsgType::postMessage )
                                SIG::sig_thrd::msgMaps[p.thrdId].postmessge(wrapper_fun);
                            else
                                SIG::sig_thrd::msgMaps[p.thrdId].sendmessage(wrapper_fun);

                            std::cout<<"Blocking waiting slot function execut"<<std::endl;
                            blockFuture.get();
                            std::cout<<"Slot function execution completed"<<std::endl;
                        }
                    }
                }
            }

    private:
        std::list<slotCfg> m_connected_slots;
        std::mutex slots_mutex;
    };
}

#define SIG_THREAD_INIT()   SIG::sig_thrd::Init_CurrentThrdSignalBuffer();
#define SIG_THREAD_CLEAR()  SIG::sig_thrd::clear_CurrentThrdSignalBuffer();

#define SIG_THREAD_EXEC(runflagName)     while(runflagName){\
                                                                                SIG::ACTION_MSG msg = SIG::sig_thrd::getMessageFromCurrentThrdSignalBuffer(-1);\
                                                                                void* r = msg.reciver;       \
                                                                                SIG::sigReciver::s_mutex.lock();\
                                                                                if(SIG::sigReciver::isExits(r) || r== nullptr){            \
                                                                                    msg.fn();               \
                                                                                }else{          \
                                                                                    std::cout<<"sigReciver does not exist!"<<std::endl;\
                                                                                }\
                                                                                SIG::sigReciver::s_mutex.unlock();\
                                                                            };

#define XSIGNAL(signame,...)                std::shared_ptr<SIG::xsignal<__VA_ARGS__>> signame =  \
                                                                  std::make_shared<SIG::xsignal<__VA_ARGS__>>();        \
                                                                  bool signame##_xsignal = SIG::AbsSignal::addWeakPtrToList(signame);
#define xemit(name) (*name)
#endif